package org.example.controller;

import lombok.extern.slf4j.Slf4j;
import org.example.commonapi.domain.R;
import org.example.commonapi.response.aippt.ThemeInfo;
import org.example.commonapi.response.fileUnderstand.FileUnderstandListener;
import org.example.commonapi.response.fileUnderstand.UploadResponse;
import org.example.commonapi.response.speechSynthesis.SpeechSynthesisListener;
import org.example.commonapi.util.JwtUtil;
import org.example.commonapi.vo.VideoVO;
import org.example.commonapi.domain.Player;
import org.example.commonapi.request.characterSimulation.AgentRequest;
import org.example.commonapi.response.characterSimulation.CharacterSimulationListener;
import org.example.commonapi.request.characterSimulation.InteractiveRequest;
import org.example.commonapi.response.bigmodel.SparkChatListener;
import org.example.service.AiChatService;
import org.example.utils.HttpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * 存放ai对话相关的Controller
 */

@RestController
@RequestMapping("/aiChat")
@Slf4j
public class AiChatController {

    @Autowired
    private AiChatService aiChatService;

    @Autowired
    private JwtUtil jwtUtil;

    // 用于角色模拟时上一次对话的id
    private String preChatId = "";

    /**
     * Ai对话功能 开启一个websocket 使用SSE进行信息传递
     * @param question
     * @return
     */
    @GetMapping(value = "/chat", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter chat(@RequestParam("question") String question,HttpServletRequest request) {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        CompletableFuture.runAsync(()->{
            StringBuilder answerCache = new StringBuilder();
            SparkChatListener sparkChatListener;
            try {
                sparkChatListener = aiChatService.chat(question, answerCache,userId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int lastIdx = 0, len = 0;
            try {
                while (!sparkChatListener.getWsCloseFlag()) {
                    if(lastIdx < (len = answerCache.length())){
                        String sendMessage = answerCache.substring(lastIdx, len);
                        // 替换所有回车换行 空格替换为占位符
                        sendMessage = sendMessage.replaceAll(" ","&#32;").replaceAll("\n", "&#92n");
                        System.out.println("发送数据=>" + sendMessage);
                        emitter.send(sendMessage);
                        lastIdx = len;
                    }
                }
                // 当数据都发送完毕时 发送一个自定义的结束标志
                emitter.send("&#92n[DONE]");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return emitter;
    }

    /**
     * 清除用户和AI的历史对话记录
     * @param request
     * @return
     */
    @GetMapping("/clearChatHistory")
    public R clearChatHistory(HttpServletRequest request) {
        return aiChatService.clearChatHistory(request);
    }

    /**
     * ai图片生成功能 参数：问题 图片宽 图片高 返回：图片base64连接
     * @param question
     * @param width
     * @param height
     * @return
     */
    @GetMapping("/draw")
    public R<String> draw(String question, Integer width, Integer height) throws Exception {
        return aiChatService.draw(question,width,height);
    }

    /**
     * 角色模拟相关接口 判断玩家是否注册
     * @param playerName
     * @return 玩家名称是否存在
     */
    @GetMapping("/judgePlayerReigster")
    public R<String> judgePlayerReigster(String playerName) throws Exception {
        return aiChatService.judgePlayerReigster(playerName);
    }

    /**
     * 角色模拟相关接口 玩家注册
     * @param player
     * @return 玩家注册后的id
     */
    @PostMapping("/playerRegister")
    public R<String> playerRegister(@RequestBody Player player,HttpServletRequest httpServletRequest) throws Exception {
        return aiChatService.playerRegister(player,httpServletRequest);
    }

    /**
     * 角色模拟相关接口 编辑玩家信息
     * @param player
     * @return 是否编辑成功
     */
    @PostMapping("/playerEdit")
    public R<String> playerEdit(@RequestBody Player player) throws Exception {
        return aiChatService.playerEdit(player);
    }

    /**
     * 角色模拟相关接口 注销玩家信息
     * @param player
     * @return 是否注销成功
     */
    @PostMapping("/playerDelete")
    public R<String> playerDelete(@RequestBody Player player) throws Exception {
        return aiChatService.playerDelete(player);
    }

    /**
     * 获取用户最新的玩家信息作为默认使用的玩家
     * @param httpServletRequest
     * @return
     */
    @GetMapping("/getPlayerInfo")
    public R<List<Player>> getPlayerInfoList(HttpServletRequest httpServletRequest) {
        return aiChatService.getPlayerInfoList(httpServletRequest);
    }

    /**
     * 角色模拟相关接口 创建人格信息
     * @param agentRequest
     * @return 新增的人格的id
     * @throws Exception
     */
    @PostMapping("/agentCreate")
    public R<String> agentCreate(@RequestBody AgentRequest agentRequest) throws Exception {
        return aiChatService.agentCreate(agentRequest);
    }

    /**
     * 角色模拟相关接口 编辑人格信息
     * @param agentRequest
     * @return 是否编辑成功
     * @throws Exception
     */
    @PostMapping("/agentEdit")
    public R<String> agentEdit(@RequestBody AgentRequest agentRequest) throws Exception {
        return aiChatService.agentEdit(agentRequest);
    }

    /**
     * 角色模拟相关接口 查询人格信息
     * @param playerId
     * @return 人格信息
     * @throws Exception
     */
    @GetMapping("/getAgentInfo")
    public R<AgentRequest> getAgentInfo(@RequestParam String playerId) throws Exception {
        return aiChatService.getAgentInfo(playerId);
    }

    /**
     * 角色模拟相关接口 删除人格信息
     * @param agentRequest
     * @return 是否成功删除
     * @throws Exception
     */
    @DeleteMapping("/agentDelete")
    public R<String> agentDelete(@RequestBody AgentRequest agentRequest) throws Exception {
        return aiChatService.agentDelete(agentRequest);
    }

    /**
     * 角色模拟相关接口 玩家生成短期记忆 玩家只能生成 obs即观察记忆便于人格理解上下文 cov对话记忆在对话时自动添加
     * @param interactiveRequest
     * @return 是否操作成功
     * @throws Exception
     */
    @PostMapping("/generateMemory")
    public R<String> generateMemory(@RequestBody InteractiveRequest interactiveRequest) throws Exception {
        return aiChatService.generateMemory(interactiveRequest);
    }

    /**
     * 角色模拟相关接口 玩家与人格进行对话
     * @param question
     * @return
     */
    @GetMapping(value = "/characterSimulationChat", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter characterSimulationChat(@RequestParam("question") String question,@RequestParam("playerId") String playerId,@RequestParam("agentId") String agentId,HttpServletRequest request) {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        // 使用UUID生成chatID
        String chatId = UUID.randomUUID().toString().substring(0, 10);
        if ( preChatId == null ) {
            preChatId = chatId;
        }
        CompletableFuture.runAsync(()->{
            StringBuilder answerCache = new StringBuilder();
            CharacterSimulationListener characterSimulationListener;
            try {
                characterSimulationListener = aiChatService.characterSimulationChat(question, answerCache,playerId,agentId,chatId,preChatId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int lastIdx = 0, len = 0;
            try {
                while (!characterSimulationListener.getWsCloseFlag()) {
                    if(lastIdx < (len = answerCache.length())){
                        String sendMessage = answerCache.substring(lastIdx, len);
                        // 替换所有回车换行 空格替换为占位符
                        sendMessage = sendMessage.replaceAll(" ","&#32;").replaceAll("\n", "&#92n");
                        System.out.println("发送数据=>" + sendMessage);
                        emitter.send(sendMessage);
                        lastIdx = len;
                    }
                }
                emitter.send("&#92n[DONE]");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        preChatId = chatId;
        return emitter;
    }

    /**
     * 图片上传接口 转换为base64链接
     * @param file
     * @return
     */
    @PostMapping("/getBase64Link")
    public R<String> getBase64Link(@RequestPart("file") MultipartFile file) throws IOException {
        return aiChatService.getBase64Link(file);
    }

    /**
     * 根据UID获取图片Base64链接
     * @param UID
     * @return
     * @throws IOException
     */
    @GetMapping("/getBase64LinkByUID")
    public R<String> getBase64LinkByUID(@RequestParam("UID") String UID) throws IOException {
        System.out.println(UID);
        return aiChatService.getBase64LinkByUID(UID);
    }

    /**
     * Ai图片理解功能 开启一个websocket 使用SSE进行信息传递
     * @param question
     * @return
     */
    @GetMapping(value = "/imageUnderStandChat", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter imageUnderStandChat(@RequestParam("question") String question,@RequestParam("UID") String UID,HttpServletRequest request) throws IOException {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        if ( UID == null ) {
            emitter.send("请先上传图片");
            return emitter;
        }
        CompletableFuture.runAsync(()->{
            StringBuilder answerCache = new StringBuilder();
            SparkChatListener sparkChatListener;
            try {
                sparkChatListener = aiChatService.imageUnderStandChat(question, answerCache,UID);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int lastIdx = 0, len = 0;
            try {
                while (!sparkChatListener.getWsCloseFlag()) {
                    if(lastIdx < (len = answerCache.length())){
                        String sendMessage = answerCache.substring(lastIdx, len);
                        // 替换所有回车换行 空格替换为占位符
                        sendMessage = sendMessage.replaceAll(" ","&#32;").replaceAll("\n", "&#92n");
                        System.out.println("发送数据=>" + sendMessage);
                        emitter.send(sendMessage);
                        lastIdx = len;
                    }
                }
                emitter.send("&#92n[DONE]");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return emitter;
    }

    /**
     * 文件理解中的文件上传功能
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/fileUnderStandUpload")
    public R<String> fileUnderStandUpload(@RequestPart("file") MultipartFile file) throws IOException {
        return aiChatService.fileUnderStandUpload(file);
    }

    /**
     * Ai文档问答功能 开启一个websocket 使用SSE进行信息传递
     * @param question
     * @return
     */
    @GetMapping(value = "/fillUnderStandChat", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter fillUnderStandChat(@RequestParam("question") String question,@RequestParam("fileId") String fileId,HttpServletRequest request) {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        CompletableFuture.runAsync(()->{
            StringBuilder answerCache = new StringBuilder();
            FileUnderstandListener fileUnderstandListener;
            try {
                fileUnderstandListener = aiChatService.fileUnderStandChat(question, answerCache,fileId);
                if ( fileUnderstandListener == null ) {
                    emitter.send("当前文件正在上传中，请稍等".getBytes());
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int lastIdx = 0, len = 0;
            try {
                while (!fileUnderstandListener.getWsCloseFlag()) {
                    if(lastIdx < (len = answerCache.length())){
                        String sendMessage = answerCache.substring(lastIdx, len);
                        // 替换所有回车换行 空格替换为占位符
                        sendMessage = sendMessage.replaceAll(" ","&#32;").replaceAll("\n", "&#92n");
                        System.out.println("发送数据=>" + sendMessage);
                        emitter.send(sendMessage);
                        lastIdx = len;
                    }
                }
                emitter.send("&#92n[DONE]");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return emitter;
    }

    /**
     * 获取AI制作PPT时的主题信息
     * @return
     */
    @GetMapping("/getAiPPTInfo")
    public R<List<ThemeInfo.Datas>> getAiPPTInfo() throws IOException {
        return aiChatService.getAiPPTInfo();
    }

    /**
     * Ai直接根据用户需求生成ppt
     * @param type
     * @param author
     * @param query
     * @param isCardNote
     * @param isCoverImg
     * @param theme
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    @GetMapping(value = "/getAiPPTWithoutAnything", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter getAiPPTWithoutAnything(HttpServletRequest request,@RequestParam("type") String type,@RequestParam("author") String author,@RequestParam("query") String query,@RequestParam("isCardNote") Boolean isCardNote,@RequestParam("isCoverImg") Boolean isCoverImg,@RequestParam("theme") String theme) throws IOException, InterruptedException {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        CompletableFuture.runAsync(()->{
            try {
                aiChatService.getAiPPTWithoutAnything(type,author,query,isCardNote,isCoverImg,theme,emitter);
            } catch (IOException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        return emitter;
    }

    /**
     * 语音合成功能 将文本转化为语音 用于机器翻译时用ai朗读
     * @param text
     * @return
     */
    @GetMapping(value = "/aiSpeechSynthesis", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter aiSpeechSynthesis(@RequestParam("text") String text,HttpServletRequest request) {
        Long userId = jwtUtil.parseJwt(request.getHeader("token")).getId();
        final SseEmitter emitter = aiChatService.getConn(userId);
        CompletableFuture.runAsync(()->{
            StringBuilder answerCache = new StringBuilder();
            SpeechSynthesisListener speechSynthesisListener;
            try {
                speechSynthesisListener = aiChatService.aiSpeechSynthesis(text, answerCache);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            int lastIdx = 0, len = 0;
            try {
                while (!speechSynthesisListener.getWsCloseFlag()) {
                    if(lastIdx < (len = answerCache.length())){
                        String sendMessage = answerCache.substring(lastIdx, len);
                        // 替换所有回车换行 空格替换为占位符
                        System.out.println("发送数据=>" + sendMessage);
                        emitter.send(sendMessage);
                        lastIdx = len;
                    }
                }
                emitter.send("&#92n[DONE]");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return emitter;
    }

}
